package com.ideaaedi.springcloud.jd.commonspring.mybatisplus.tenant;

import com.ideaaedi.commonspring.parser.SpelUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.core.Ordered;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;
import org.springframework.util.Assert;

import java.lang.reflect.Method;

/**
 * 对{@link TenantDataScope}进行支持实现
 *
 * @author <font size = "20" color = "#3CAA3C"><a href="https://gitee.com/JustryDeng">JustryDeng</a></font> <img
 * src="https://gitee.com/JustryDeng/shared-files/raw/master/JustryDeng/avatar.jpg" />
 * @since 2021.0.5.B
 */
@Slf4j
@Aspect
@Component
@Order(Ordered.HIGHEST_PRECEDENCE + 90)
public class TenantAspect {
    
    @Around("@annotation(tenantDataScopeAnno)")
    public Object aroundAdvice(ProceedingJoinPoint thisJoinPoint, TenantDataScope tenantDataScopeAnno) throws Throwable {
        String tenant = tenantDataScopeAnno.value();
        Method method = ((MethodSignature) thisJoinPoint.getSignature()).getMethod();
        Object[] arguments = thisJoinPoint.getArgs();
        if (StringUtils.isNotBlank(tenant)) {
            tenant = SpelUtil.parseSpel(method, arguments, String.class, tenant);
        }
        log.info("TenantAop curr tenant is {}", tenant);
        try {
            Assert.isTrue(StringUtils.isNotBlank(tenant), "tenant cannot be blank.");
            TenantDataScopeBO tenantDataScopeBO = TenantProvider.TENANT_HOLDER.get();
            if (tenantDataScopeBO == null) {
                TenantProvider.TENANT_HOLDER.set(new TenantDataScopeBO(tenant));
            } else {
                tenantDataScopeBO.getTenantDeque().addFirst(tenant);
            }
            return thisJoinPoint.proceed();
        } finally {
            TenantDataScopeBO tenantDataScopeBO = TenantProvider.TENANT_HOLDER.get();
            if (tenantDataScopeBO != null) {
                tenantDataScopeBO.getTenantDeque().pollFirst();
                if (tenantDataScopeBO.getTenantDeque().size() <= 0) {
                    TenantProvider.TENANT_HOLDER.remove();
                }
            }
        }
    }
}
